home *** CD-ROM | disk | FTP | other *** search
- /*
- * copyfile.c - routines to copy a file from server to client
- */
- #include "RevRdist.h"
- #include "dispatch.h"
- #include "desktop.h"
-
- static Longint lastflush = 0;
- static void updateSpace(void);
-
- /*
- * Methods for copying file from server to client
- */
- typedef enum copy_method
- {
- CP_NEW_FILE /* no existing client file--just copy */
- ,CP_BURN_BRIDGE /* delete existing file before copy */
- ,CP_RENAME /* copy to temp file, then rename */
- ,CP_EXCHANGE /* copy to temp file, then exchange catalog entries */
- } copy_method_e;
-
- #define CLSIZE(n) ((n + ClientClpM) & ~ClientClpM)
-
- /*
- *=========================================================================
- * copyFile (sp, cp, name) - copy file from server to client
- * entry: first param = pointer to catalog list node for server file
- * second param = pointer to catalog list node for client file
- * the information here is updated if the copy succeeds.
- * third param = name of client folder to get file
- *=========================================================================
- */
- DISPATCHED (copyFile)
- {
- #define COPYBUFSZ 65536
- struct lm
- {
- frame_t f;
- cnode_t * sp; /* copy of first arg */
- cnode_t * cp; /* copy of second arg */
- StringPtr dname; /* copy of third arg */
- Ptr bufp; /* ptr to I/O buffer */
- StringPtr fn; /* file name used */
- Boolean quit; /* quit when copy complete */
- copy_method_e meth; /* copy method to use */
- HParamBlockRec src; /* param block for reading */
- HParamBlockRec dst; /* param block for writing */
- };
- typedef struct lm lm_t;
- register lm_t * m;
- Ptr bufp; /* temp copy of lm.bufp */
- OSErr error;
- Longint cl, sl; /* client, server byte counts */
- StringPtr fn; /* temp ptr to file name */
- copy_method_e meth; /* local copy of lm.meth */
- short result; /* our return value */
- Integer temp;
- Ptr paramv[1]; /* return value vector */
- CInfoPBRec cb; /* get/setCatInfo param block */
- Str255 cbuf; /* buffer for numeric conversions */
- HParamBlockRec tmp; /* for temp file manipulations */
-
- m = *(lm_t **)fh;
- result = request;
- error = 0;
- switch (request)
- {
- case R_INIT:
- if (ClueID = resizeFrame (fh, sizeof (lm_t)))
- return R_ERROR;
- if ((bufp = NewPtr (COPYBUFSZ)) == nil)
- {
- if ((ClueID = MemError()) == 0)
- ClueID = memFullErr;
- return R_ERROR;
- }
- m = *(lm_t **)fh;
- m->sp = (cnode_t *)argv[0];
- m->cp = (cnode_t *)argv[1];
- m->dname = (StringPtr)argv[2];
- m->bufp = bufp;
- m->f.state = 1;
- return R_CONT;
-
- case R_CONT:
- /*
- * Handle only the first step of R_CONT here, and the rest after
- * the request switch.
- */
- if (m->f.state == 1)
- {
- sl = m->sp->in.f.fileLen + m->sp->in.f.rsrcLen;
- NumToString (sl, cbuf);
- notice (L_COPYING, cbuf, m->sp->name, m->dname, nil);
- m->f.state = 2;
- /*
- * First, if there is no space, and cannot be space, give up.
- * Next, determine which copy method to use.
- */
- sl = CLSIZE(m->sp->in.f.fileLen) + CLSIZE(m->sp->in.f.rsrcLen);
- if (sl >= ClientSp)
- updateSpace();
- if (sl >= ClientSp)
- {
- cl = CLSIZE(m->cp->in.f.fileLen) + CLSIZE(m->cp->in.f.rsrcLen);
- if (sl >= ClientSp + cl)
- {
- error = dskFulErr;
- Clue1 = "\pupdateSpace";
- goto syserrexit;
- }
- /*
- * Must delete client file before copy
- */
- meth = CP_BURN_BRIDGE;
- }
- else
- {
- if (!m->cp->dirID)
- meth = CP_NEW_FILE;
- else
- {
- if (ClientVIB.vMAttrib & (1<<bHasFileIDs))
- meth = CP_EXCHANGE;
- else
- meth = CP_RENAME;
- }
- }
- m->meth = meth;
- return R_CONT;
- }
- break;
-
- case R_BACKOUT:
- case R_QUIT:
- goto cleanexit;
- }
-
- /*
- * The body of the R_CONT code:
- */
- if (Flags & PF_LISTONLY)
- goto cleanexit;
- /*
- * Honor quit only if we are not the startup application, so that
- * we don't leave files missing if an antsy student cancels
- * an automatic RevRdist.
- */
- if (Quit)
- {
- Quit = false;
- if (Flags & PF_STARTUP)
- m->quit = true;
- else
- warning (E_DOQUIT, nil); /* ask if okay to continue */
- }
- if (Quit)
- goto cleanexit;
- switch (m->f.state)
- {
- case 2:
- /*
- * open the source file on the server.
- * We open either the data or resource fork.
- * Only if that succeeds, create the client destination file.
- */
- m->src.fileParam.ioNamePtr = m->sp->name;
- m->src.fileParam.ioVRefNum = ServerVol;
- m->src.ioParam.ioPermssn = fsRdPerm;
- m->src.fileParam.ioDirID = m->sp->parID;
- if (m->sp->in.f.fileLen)
- error = PBHOpen (&m->src, false);
- else if (m->sp->in.f.rsrcLen)
- error = PBHOpenRF (&m->src, false);
- else
- error = 0;
- if (error)
- {
- if (error == fnfErr)
- {
- notice (L_MISSING, m->sp->name, nil);
- goto cleanexit;
- }
- Clue1 = "\pPBHOpen";
- goto syserrexit;
- }
- /*
- * Do method-dependent pre-copy setup and set file name
- */
- switch (m->meth)
- {
- case CP_NEW_FILE:
- fn = m->cp->name; /* copy directly to file */
- break;
- case CP_BURN_BRIDGE:
- if (m->cp->dirID)
- {
- /*
- * If the file already exists, delete it
- */
- error = discard (m->cp, false);
- if (error)
- {
- ClueID = error;
- if (error == fBsyErr)
- notice (L_FILE, "\pdiscard", m->cp->name, nil);
- else
- warning (E_FILE, "\pdiscard", m->cp->name, nil);
- goto cleanexit;
- }
- }
- fn = m->cp->name; /* copy directly */
- break;
- case CP_RENAME:
- case CP_EXCHANGE:
- fn = TempName; /* use temp file */
- break;
- }
- m->fn = fn;
- m->dst.fileParam.ioNamePtr = fn;
- m->dst.fileParam.ioVRefNum = ClientVol;
- m->dst.fileParam.ioDirID = m->cp->parID;
- error = PBHCreate (&m->dst, false);
- if (error)
- {
- ClueID = error;
- warning (E_FILE, "\pcopyfile PBHCreate", fn, nil);
- goto cleanexit;
- }
- /*
- * Set file creator and type so we can get rid of it
- * easily if something goes wrong. Ignore errors.
- */
- error = PBHGetFInfo (&m->dst, false);
- if (error == 0)
- {
- m->dst.fileParam.ioDirID = m->cp->parID;
- m->dst.fileParam.ioFlFndrInfo.fdType = TYPE_TEMP;
- m->dst.fileParam.ioFlFndrInfo.fdCreator = CREATOR;
- error = PBHSetFInfo (&m->dst, false);
- }
- /*
- * If the file has a data fork, set up to copy it.
- */
- if ((sl = m->sp->in.f.fileLen))
- {
- m->dst.ioParam.ioPermssn = fsRdWrPerm;
- error = PBHOpen (&m->dst, false);
- if (error)
- {
- Clue1 = "\pPBHOpen";
- goto syserrexit;
- }
- /*
- * Reduce fragmentation by allocating contiguously
- */
- m->dst.ioParam.ioReqCount = sl;
- error = PBAllocContig ((ParmBlkPtr)&m->dst, false);
- m->f.state = 3;
- }
- else
- m->f.state = 4; /* skip data fork copy */
- break;
-
- case 3:
- case 5:
- /*
- * copy one fork in COPYBUFSZ chunks
- */
- m->src.ioParam.ioBuffer = m->bufp;
- m->src.ioParam.ioReqCount = COPYBUFSZ;
- m->src.ioParam.ioActCount = 0;
- m->src.ioParam.ioPosMode = fsAtMark;
- error = PBRead ((ParmBlkPtr)&m->src, false);
- if ((sl = m->src.ioParam.ioActCount) != 0)
- {
- m->dst.ioParam.ioBuffer = m->bufp;
- do
- {
- m->dst.ioParam.ioReqCount = sl;
- m->dst.ioParam.ioActCount = 0;
- m->dst.ioParam.ioPosMode = fsAtMark;
- error = PBWrite ((ParmBlkPtr)&m->dst, false);
- if (error)
- break;
- sl -= m->dst.ioParam.ioActCount;
- m->dst.ioParam.ioBuffer += m->dst.ioParam.ioActCount;
- } while (sl > 0);
- if (error)
- {
- Clue1 = "\pPBWrite";
- goto syserrexit;
- }
- }
- else if (error && error != eofErr)
- {
- Clue1 = "\pPBRead";
- goto syserrexit;
- }
- else if (error == eofErr)
- {
- /*
- * one fork copy complete.
- */
- (void) PBClose ((ParmBlkPtr)&m->src, false);
- m->src.ioParam.ioRefNum = 0;
- error = PBClose ((ParmBlkPtr)&m->dst, false);
- m->dst.ioParam.ioRefNum = 0;
- if (error)
- {
- Clue1 = "\pPBClose";
- goto syserrexit;
- }
- m->f.state++;
- }
- break;
-
- case 4:
- /*
- * set up to copy resource fork
- * open source and destination forks
- */
- if ((sl = m->sp->in.f.rsrcLen) == 0)
- {
- m->f.state = 6;
- break;
- }
- /*
- * Open the src resource fork if we didn't do so in state 2
- */
- if (m->src.ioParam.ioRefNum == 0)
- {
- ZERO (m->src);
- m->src.fileParam.ioNamePtr = m->sp->name;
- m->src.fileParam.ioVRefNum = ServerVol;
- m->src.ioParam.ioPermssn = fsRdPerm;
- m->src.fileParam.ioDirID = m->sp->parID;
- error = PBHOpenRF (&m->src, false);
- if (error)
- {
- Clue1 = "\pPBHOpenRF";
- goto syserrexit;
- }
- }
- ZERO (m->dst);
- m->dst.fileParam.ioNamePtr = m->fn;
- m->dst.fileParam.ioVRefNum = ClientVol;
- m->dst.ioParam.ioPermssn = fsRdWrPerm;
- m->dst.fileParam.ioDirID = m->cp->parID;
- error = PBHOpenRF (&m->dst, false);
- if (error)
- {
- Clue1 = "\pPBHOpenRF";
- goto syserrexit;
- }
- m->dst.ioParam.ioReqCount = sl;
- error = PBAllocContig ((ParmBlkPtr)&m->dst, false);
- m->f.state++;
- break;
-
- case 6:
- /*
- * Both forks copied, do post-copy, method-dependent cleanup
- */
- switch (m->meth)
- {
- case CP_NEW_FILE:
- cl = 0;
- break;
- case CP_BURN_BRIDGE:
- cl = 0; /* discard has already adjusted */
- break;
- case CP_EXCHANGE:
- case CP_RENAME:
- if (m->cp->attrib & fLocked)
- error = unlock (m->cp);
- if (m->meth == CP_EXCHANGE)
- {
- m->dst.fidParam.ioSrcDirID = m->cp->parID;
- m->dst.fidParam.ioDestNamePtr = m->cp->name;
- m->dst.fidParam.ioDestDirID = m->cp->parID;
- error = PBExchangeFiles (&m->dst, false);
- if (error == 0)
- {
- fn = m->fn;
- goto purge_temp;
- }
- if (error != paramErr)
- {
- Clue1 = "\pPBExchangeFiles";
- goto syserrexit;
- }
- /* Exchange unsupported, try rename */
- }
- /*
- * First, rename the old file to a safe name
- */
- fn = TempName2;
- for (temp = 0; temp < 2; temp++)
- {
- ZERO(tmp);
- tmp.fileParam.ioNamePtr = m->cp->name;
- tmp.fileParam.ioVRefNum = ClientVol;
- tmp.fileParam.ioDirID = m->cp->parID;
- tmp.ioParam.ioMisc = (Ptr)fn;
- error = PBHRename (&tmp, false);
- if (temp == 0 && error == dupFNErr)
- {
- tmp.fileParam.ioNamePtr = fn;
- tmp.ioParam.ioMisc = 0;
- error = PBHDelete (&tmp, false);
- continue;
- }
- break;
- }
- Clue1 = "\pPBHRename";
- if (error)
- goto syserrexit;
- /*
- * Now, rename the new copy to the right name
- */
- m->dst.fileParam.ioNamePtr = m->fn;
- m->dst.fileParam.ioDirID = m->cp->parID;
- m->dst.ioParam.ioMisc = (Ptr)m->cp->name;
- error = PBHRename (&m->dst, false);
- if (error)
- {
- ZERO(tmp);
- tmp.fileParam.ioNamePtr = TempName2;
- tmp.fileParam.ioVRefNum = ClientVol;
- tmp.fileParam.ioDirID = m->cp->parID;
- tmp.ioParam.ioMisc = (Ptr)m->cp->name;
- (void) PBHRename (&tmp, false);
- goto syserrexit;
- }
- purge_temp:
- /*
- * Last, delete the renamed old copy
- */
- ZERO(tmp);
- tmp.fileParam.ioNamePtr = fn;
- tmp.fileParam.ioVRefNum = ClientVol;
- tmp.fileParam.ioDirID = m->cp->parID;
- error = PBHDelete (&tmp, false);
- Clue1 = "\pPBHDelete";
- if (error == fBsyErr)
- {
- cnode_t tnode;
-
- error = getInfo(fn, ClientVol, m->cp->parID, &tnode);
- if (error)
- Clue1 = "\pgetInfo";
- else
- {
- Clue1 = "\pmoveToJunk";
- error = moveToJunk (&tnode);
- }
- }
- if (error)
- {
- goto syserrexit;
- }
- cl = CLSIZE(m->cp->in.f.fileLen) + CLSIZE(m->cp->in.f.rsrcLen);
- break;
- }
- sl = CLSIZE(m->sp->in.f.fileLen) + CLSIZE(m->sp->in.f.rsrcLen);
- ClientSp = ClientSp + cl - sl;
- /*
- * Copy Finder information
- */
- ZERO (cb);
- cb.hFileInfo.ioNamePtr = m->cp->name;
- cb.hFileInfo.ioVRefNum = ClientVol;
- cb.hFileInfo.ioDirID = m->cp->parID;
- error = PBGetCatInfo (&cb, false);
- if (error)
- {
- Clue1 = "\pPBGetCatInfo";
- goto syserrexit;
- }
- cb.hFileInfo.ioDirID = m->cp->parID;
- temp = cb.hFileInfo.ioFlFndrInfo.fdFldr;
- cb.hFileInfo.ioFlFndrInfo = m->sp->in.f.finfo;
- // cb.hFileInfo.ioFlFndrInfo.fdFlags &= ~0x0100; /* clear inited bit */
- /*
- * If server protected, hide the client copy, because we cannot
- * protect it.
- */
- if (m->sp->attrib & fProtect)
- {
- notice (L_PROTECT, m->cp->name, nil);
- cb.hFileInfo.ioFlFndrInfo.fdFlags |= fInvisible;
- }
- cb.hFileInfo.ioFlFndrInfo.fdFldr = temp;
- cb.hFileInfo.ioFlCrDat = m->sp->crDate;
- cb.hFileInfo.ioFlMdDat = m->sp->mdDate;
- error = PBSetCatInfo (&cb, false);
- if (error)
- {
- Clue1 = "\pPBSetCatInfo";
- goto syserrexit;
- }
- saveCatInfo (&cb, m->cp);
-
- desktop_update (m->sp, m->cp);
- /*
- * Doing a Flush after every file slowed things down too much
- * on lots of small files, so we flush only every so often
- */
- sl = TickCount ();
- if (sl - lastflush > 60 * 20)
- {
- m->dst.fileParam.ioNamePtr = nil;
- error = PBFlushVol ((ParmBlkPtr)&m->dst, false);
- if (error)
- {
- Clue1 = "\pPBFlushVol";
- goto syserrexit;
- }
- lastflush = sl;
- }
- goto cleanexit;
- }
- return result;
-
- syserrexit:
- ClueID = error;
- /*
- * NFS/Share returns permErr on open of file opened with exclusive
- * access by someone else. Note it and continue.
- */
- if (error == permErr)
- {
- notice (L_FILE, "\pcopyFile", m->sp->name, nil);
- }
- else
- {
- Clue2 = nil;
- warning (E_SYS, "\pcopyFile", nil);
- }
- /*
- * If the disk fills and we are running unattended, ignore the
- * error so we can finish and possibly make room for next time
- */
- if ((Flags & PF_STARTUP) && error == dskFulErr)
- Quit = false;
- cleanexit:
- if (GetHandleSize ((Handle)fh) >= sizeof (lm_t))
- {
- if (m->dst.ioParam.ioRefNum)
- (void) PBClose ((ParmBlkPtr)&m->dst, false);
- if (m->src.ioParam.ioRefNum)
- (void) PBClose ((ParmBlkPtr)&m->src, false);
- if (error && m->f.state > 2)
- {
- fn = m->dst.fileParam.ioNamePtr;
- ZERO (m->dst);
- m->dst.fileParam.ioNamePtr = fn;
- m->dst.fileParam.ioVRefNum = ClientVol;
- m->dst.fileParam.ioDirID = m->cp->parID;
- (void) PBHDelete (&m->dst, false);
- }
- if (m->bufp)
- DisposPtr (m->bufp);
- }
- if (error)
- updateSpace();
- else
- statMsgClr ();
- if (m->quit)
- Quit = true;
- paramv[0] = (Ptr)&error;
- return (popCall (result, paramv));
- }
-
-
-
- /*
- *=========================================================================
- * updateSpace() - bring ClientSp variable up to date
- * entry: ClientVol set
- * exit: ClientSp updated
- *=========================================================================
- */
- static void
- updateSpace(void)
- {
- OSErr error;
- HParamBlockRec hpb;
-
- ZERO (hpb);
- hpb.volumeParam.ioVRefNum = ClientVol;
- error = PBHGetVInfo (&hpb, false);
- if (error == 0)
- {
- ClientSp = (unsigned long)(unsigned)hpb.volumeParam.ioVFrBlk
- * (unsigned)hpb.volumeParam.ioVAlBlkSiz;
- }
- }